package org.jeecg.modules.engineering.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.MD5Util;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.StringUtils;
import org.jeecg.modules.engineering.entity.*;
import org.jeecg.modules.engineering.service.*;
import org.jeecg.modules.engineering.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.time.Instant;
import java.util.*;

/**
 * @Description: 设备Api接口
 * @Author: jeecg-boot
 * @Date:   2019-08-22
 * @Version: V1.0
 */
@Slf4j
@Api(tags="设备Api接口")
@RestController
@RequestMapping("/api/equip")
public class EquipDataApiController {
	@Autowired
	private IEquipInfoService equipInfoService;
	@Autowired
	private IEquipEventInfoService equipEventInfoService;
	@Autowired
	private IEquipDataCollectorService equipDataCollectorService;
	@Autowired
	private IEquipDataApiService equipDataApiService;
	@Autowired
	private IEquipEventSortService equipEventSortService;
	@Autowired
	private IEquipCollectItemDetailService equipCollectItemDetailService;
	@Autowired
	private IEquipCollectItemService equipCollectItemService;
	@Autowired
	private IEquipEventSortDetailService equipEventSortDetailService;
	@Autowired
	private RedisUtil redisUtil;
	@Autowired
	private RestTemplate restTemplate;

	private static final String CN_CODE = "30997267ddc991839a2f8xinfu";


	/**
	 * 设备状态统计-项目级
	 * @param projectId  小区/项目
	 * @param sortId 分类
	 * @return
	 */
	@AutoLog(value = "设备状态统计-项目级-所属分类")
	@ApiOperation(value="设备状态统计-项目级查询-所属分类", notes="设备状态统计-项目级查询-所属分类")
	@PostMapping(value = "/findStatusByProjectAndSort")
	public Result<List<EquipStatusReport>> findStatusByProjectAndSort(@RequestParam("projectId") String projectId,@RequestParam("sortId") String sortId) {
		List<EquipStatusReport> list;
		try {
			list = equipInfoService.findStatusByProjectAndSort(projectId,sortId);
			return Result.ok(list);
		} catch (Exception e) {
			log.error(e.getMessage(),e);
			return Result.error(e.getMessage());
		}
	}
	@AutoLog(value = "设备状态统计-项目级-归属系统")
	@ApiOperation(value="设备状态统计-项目级查询-归属系统", notes="设备状态统计-项目级查询-归属系统")
	@PostMapping(value = "/findStatusByProjectAndSystem")
	public Result<List<EquipStatusReport>> findStatusByProjectAndSystem(@RequestParam("projectId") String projectId,@RequestParam("topSystem") String topSystem) {
		List<EquipStatusReport> list;
		try {
			list = equipInfoService.findStatusByProjectAndSystem(projectId,topSystem);
			return Result.ok(list);
		} catch (Exception e) {
			log.error(e.getMessage(),e);
			return Result.error(e.getMessage());
		}
	}

	@AutoLog(value = "设备状态统计-项目级-归属系统")
	@ApiOperation(value="设备状态统计-项目级查询-归属系统", notes="设备状态统计-项目级查询-归属系统")
	@PostMapping(value = "/getSmartDeviceCenter")
	public Result<SmartDeviceCenterOne> getSmartDeviceCenter(@RequestParam("projectId") String projectId,@RequestParam("topSystem") String topSystem){
		try {
			//归属系统的设备总数以及异常设备数
			SmartDeviceCenterOne smartDeviceCenterOne = new SmartDeviceCenterOne();
			List<EquipStatusReport> statusList = equipInfoService.findStatusByProjectAndSystem(projectId,topSystem);
			Integer total = 0,abTotal = 0;
			for (EquipStatusReport statusReport:statusList){
				total += statusReport.getStatusNum();
				if (!CommonConstant.EQUIP_STATUS_NORMAL.equals(statusReport.getEquipStatus())){
					abTotal += statusReport.getStatusNum();
				}
			}
			if (total != 0){
				BigDecimal bigTotal = new BigDecimal(total);
				BigDecimal bigNormal = new BigDecimal(total - abTotal);
				BigDecimal normalRate = bigNormal.multiply(new BigDecimal(100)).divide(bigTotal,2,BigDecimal.ROUND_HALF_UP);
				smartDeviceCenterOne.setNormalRate(normalRate.toString());
			} else {
				smartDeviceCenterOne.setNormalRate("0");
			}
			//当月处理的事件数和未处理数
			Calendar ca = Calendar.getInstance();
			List<EquipEventInfoProcess> currentProcessList = equipInfoService.findProcessByProjectAndDate(projectId,topSystem,ca.getTime());
			//      本月总事件         本月已处理事件				本月未处理事件
			Integer currentTotal = 0,currentProcessedTotal = 0,currentUnProcessTotal = 0;
			for (EquipEventInfoProcess process:currentProcessList){
				currentTotal += process.getProcessNum();
				if (1 == process.getProcessStatus()){
					currentProcessedTotal += process.getProcessNum();
				} else {
					currentUnProcessTotal += process.getProcessNum();
				}
			}
			//上月事件
			ca.add(Calendar.MONTH,-1);
			List<EquipEventInfoProcess> prevProcessList = equipInfoService.findProcessByProjectAndDate(projectId,topSystem,ca.getTime());
			Integer prevTotal = 0;
			for (EquipEventInfoProcess prev:prevProcessList){
				prevTotal += prev.getProcessNum();
			}
			BigDecimal bigCurrent = new BigDecimal(currentTotal);
			BigDecimal bigPrev = new BigDecimal(prevTotal);
			if (bigPrev.compareTo(BigDecimal.ZERO) == 0){
				smartDeviceCenterOne.setMonthRate("-");
			} else {
				BigDecimal monthRate = bigCurrent.subtract(bigPrev).multiply(new BigDecimal(100)).divide(bigPrev,1,BigDecimal.ROUND_HALF_UP);
				smartDeviceCenterOne.setMonthRate(monthRate.toString());
			}
			smartDeviceCenterOne.setEquipTotal(total);
			smartDeviceCenterOne.setAbNormalTotal(abTotal);
			smartDeviceCenterOne.setCurrentEventTotal(currentTotal);
			smartDeviceCenterOne.setProcessedNum(currentProcessedTotal);
			smartDeviceCenterOne.setUnProcessNum(currentUnProcessTotal);
			smartDeviceCenterOne.setTopSystem(topSystem);
			return Result.ok(smartDeviceCenterOne);
		} catch (Exception e) {
			log.error(e.getMessage(),e);
			return Result.error(e.getMessage());
		}
	}



	@AutoLog(value = "设备各事件合计数-项目级")
	@ApiOperation(value="设备各事件合计数-项目级查询", notes="设备各事件合计数-项目级查询")
	@PostMapping(value = "/findEventInfoSumByProject")
	public Result<List<EquipEventInfoSum>> findEventInfoSumByProject(@RequestParam("projectId") String projectId,
																	 @RequestParam("levelList") String levelList,
																	 @RequestParam(value = "startTime",required = false) Date startTime){
		try {
			List<EquipEventInfoSum> sumList = equipEventInfoService.findEventInfoSumByProject(projectId,levelList,startTime);
			return Result.ok(sumList);
		} catch (Exception e) {
			log.error(e.getMessage(),e);
			return Result.error(e.getMessage());
		}
	}

	@AutoLog(value = "未处理事件(事件分类别)合计数-项目级")
	@ApiOperation(value="未处理事件(事件分类别)合计数-项目级查询", notes="未处理事件(事件分类别)合计数-项目级查询")
	@PostMapping(value = "/findUnProcessByProjectAndSystem")
	public Result<List<EventProcessStatus>> findUnProcessByProjectAndSystem(@RequestParam("projectId") String projectId,@RequestParam("topSystem") String topSystem){
		try {
			List<EventProcessStatus> sumList = equipEventInfoService.findUnProcessByProjectAndSystem(projectId,topSystem);
			return Result.ok(sumList);
		} catch (Exception e) {
			log.error(e.getMessage(),e);
			return Result.error(e.getMessage());
		}
	}


	@AutoLog(value = "设备事件列表-项目级")
	@ApiOperation(value="设备事件列表-项目级查询", notes="设备事件列表-项目级查询")
	@PostMapping(value = "/findEventInfoByProject")
	public Result<EquipEventReport> findEventInfoByProject(@RequestParam("projectId") String projectId, @RequestParam("minLevel") Integer minLevel, @RequestParam("maxLevel")Integer maxLevel) {
		try {
			List<EquipEventInfoExt> infoList = equipEventInfoService.findEventInfoByProject(projectId,minLevel,maxLevel);
			List<EquipEventInfoSum> sumList = equipEventInfoService.findEventInfoSumByProject(projectId,null,null);
			Map<Integer,EquipEventInfoSum> sumMap = new HashMap<>();
			for (EquipEventInfoSum infoSum:sumList){
				sumMap.put(infoSum.getWarningLevel(),infoSum);
			}
			List<EquipEventInfoSum> sumListRes = new LinkedList<>();
			for (int i=minLevel;i<=maxLevel;i=i+10){
				EquipEventInfoSum infoSumTemp = sumMap.get(i);
				if (infoSumTemp == null){
					infoSumTemp = new EquipEventInfoSum();
					infoSumTemp.setInfoSum(0);
					infoSumTemp.setWarningLevel(i);
				}
				sumListRes.add(infoSumTemp);
			}
			EquipEventReport report = new EquipEventReport();
			report.setEventInfoList(infoList);
			report.setEventInfoSumList(sumListRes);
			return Result.ok(report);
		} catch (Exception e) {
			log.error(e.getMessage(),e);
			return Result.error(e.getMessage());
		}
	}


	//@AutoLog(value = "定时任务-采集数据")
	@ApiOperation(value="定时任务-采集数据", notes="定时任务-采集数据")
	@RequestMapping(value = "/collectData")
	@Async("asyncExecutor")
	public void collectData(){
		long startTime = System.currentTimeMillis();
		System.out.println("equip模块开始采集数据");
		try {
			List<EquipDataCollector> list = equipDataCollectorService.selectAll(true);
			if(list != null && list.size() > 0){
				for (EquipDataCollector equipDataCollector : list){
					boolean result = collectData(equipDataCollector.getId(),equipDataCollector.getCollectorName(),equipDataCollector.getCollectorUrl());
					System.out.println(equipDataCollector.getCollectorName()+":数据采集总花费毫秒数" + (System.currentTimeMillis()-startTime)+":结果为："+(result?"成功":"失败"));
				}
			}else{
				log.info("采集商列表为空，采集结束");
			}
		} catch (Exception e) {
			log.error(e.getMessage(),e);
			System.out.println("数据采集总花费毫秒数" + (System.currentTimeMillis()-startTime));
		}
	}


	public boolean collectData(String id,String name,String url) {
		log.error("code"+name+";url="+url);
		List<CollectDataApiParam> params = equipInfoService.getcollectParam(id);
		StringBuilder sb = new StringBuilder();
		if(params != null && params.size() > 0){
			for(CollectDataApiParam item : params){
				sb.append(",")
						.append(item.getEquipOutCode())
						.append("-")
						.append(item.getCollectCode())
						.append("-")
						.append(item.getOutCollectCode());
			}
			sb.deleteCharAt(0);
			String token = MD5Util.MD5Encode(sb.toString()+CN_CODE,"UTF-8").toUpperCase();
			MultiValueMap<String, String> map= new LinkedMultiValueMap<>();
			map.add("token",token);
			map.add("data",sb.toString());
			log.error("token="+token+":data="+sb.toString());
			JSONObject jsonObject =  restTemplate.postForObject(url,map, JSONObject.class);
			if(jsonObject == null){
				log.info("返回的采集信息为空,接口失败");
				return false;
			}
			log.info(DateUtils.now()+" : 采集结果为："+jsonObject.toJSONString());
			Integer code = jsonObject.getInteger("code");
			if(code == null || !code.equals(200)){
				String msg = jsonObject.getString("message");
				log.error(String.format("获取的结果异常，异常码：%s,错误信息：%s",code,msg));
				throw new RuntimeException(String.format("获取的结果异常，异常码：%s,错误信息：%s",code,msg));
			}else{
				JSONArray array = jsonObject.getJSONArray("result");
				List<CollectData> collectDatas = JSONArray.parseArray(array.toJSONString(),CollectData.class);
				if(collectDatas == null || collectDatas.size() == 0){
					throw new RuntimeException("采集数据为空");
				}
				int count = (collectDatas.size()-1)/CommonConstant.BATCH_SIZE+1;
				for (int i = 1;i <= count ;i++){
					if(i == count){
						equipDataApiService.asyncCollectData(collectDatas.subList((i-1)*CommonConstant.BATCH_SIZE,collectDatas.size()));
					}else{
						equipDataApiService.asyncCollectData(collectDatas.subList((i-1)*CommonConstant.BATCH_SIZE,i*CommonConstant.BATCH_SIZE));
					}
				}
			}
		}else{
			log.info(name+"需要采集的项为空");
		}
		return true;
	}

	/**
	 * 同步电梯的报警信息
	 * @return
	 */
	//@AutoLog(value = "定时任务-同步电梯异常告警信息")
	@ApiOperation(value="定时任务-同步电梯异常告警信息", notes="定时任务-同步电梯异常告警信息")
	@Async("asyncExecutor")
	@RequestMapping(value = "/syncLiftEvent")
	public void syncLiftEvent() {
		System.out.println(DateUtils.now()+"开始同步电梯的报警信息");
		List<EquipDataCollector> list = equipDataCollectorService.selectAll(false);
		if(list == null || list.size() == 0){
			return;
		}
		Map<String,EquipEventInfo> sumInfoMap = new HashMap<>();
		for(EquipDataCollector collector : list){
			//处理维小保电梯的事件同步
			if("WXB".equals(collector.getCollectorCode())){
				List<EquipInfo> infos = equipInfoService.getEquipInfoByCollectorId(collector.getId());
				if(infos == null || infos.size() == 0){
					continue;
				}
				Object lastTimeObj = redisUtil.get(CommonConstant.SYNC_LAST_TIME+collector.getCollectorCode());
				long endTime = Instant.now().getEpochSecond();//获取当此获取告警视频的结束时间
				long startTime;
				if(lastTimeObj != null){
					startTime = Long.parseLong(lastTimeObj.toString()) +1;
				}else{
					startTime = endTime - 60 * 5; //若session中不存在，则获取最近5分钟的告警视频
				}
				if(startTime > endTime){
					//若开始时间大于结束时间，则不调用接口拉取数据
					log.info("开始事件大于结束事件，此次获取维小保电梯任务放弃执行");
					continue;
				}
				redisUtil.set(CommonConstant.SYNC_LAST_TIME+collector.getCollectorCode(),endTime);
				for(EquipInfo info : infos){
					List<EquipEventInfo> equipEventInfoList = equipDataApiService.syncListEventByOutCode(info,collector,startTime,endTime);
					for (EquipEventInfo equipEventInfo:equipEventInfoList){
						if (CommonConstant.EVENT_WARNING_MIDDLE == equipEventInfo.getWarningLevel()
								|| CommonConstant.EVENT_WARNING_MAX == equipEventInfo.getWarningLevel()){
							sumInfoMap.put(equipEventInfo.getProjectId(),equipEventInfo);
						}
					}
				}
			}
		}
		sumInfoMap.forEach((k,v)->{
			/*List<SysUser> userList = userMapper.findUserByProjectId(k);
			StringBuilder sb = new StringBuilder();
			if (userList.size() > 0 ){
				userList.forEach(sysUser -> {
					sb.append(sysUser.getId());
					sb.append(";");
				});
							}*/
			//webSocketSendService.apiSend("e9ca23d68d884d4ebb19d07889727dae", CommonConstant.SOCKET_EVENT_INFO,v.getTenantId());
		});

	}


	/**
	 * 获取电梯的基本信息
	 * @return
	 */
	@RequestMapping(value = "/getLiftBaseInfo")
	public Result<?> getLiftBaseInfo(String liftCodes) {
		System.out.println("获取电梯的状态信息");
		if(StringUtils.isEmpty(liftCodes)){
			return null;
		}
		List<String> lifts = Arrays.asList(liftCodes.split(","));
		JSONObject json = equipDataApiService.getLiftBaseInfo(lifts);
		return Result.ok(json);
	}

	/**
	 * 获取电梯的列表
	 *
	 * @return
	 */
	@RequestMapping(value = "/getLifts")
	public Result<?> getLifts() {
		List<String> codes = new ArrayList<>();
		JSONObject result = null;
		JSONObject json = equipDataApiService.syncLiftList();
		if ("0".equals(json.getString("code"))) {
			JSONArray data = json.getJSONArray("data");
			for (Object obj : data) {
				JSONObject lift = (JSONObject) obj;
				String code = lift.getString("registerCode");
				if (StringUtils.isEmpty(code)) {
					log.info("code为空");
				} else {
					codes.add(code);
				}
			}
			if (codes.size() > 0) {
				List<EquipInfo> infos = new ArrayList<>();
				result = equipDataApiService.getLiftBaseInfo(codes);
				if ("0".equals(result.getString("code"))) {
					JSONArray liftDatas = result.getJSONArray("data");
					for (Object liftObj : liftDatas) {
						JSONObject lift = (JSONObject) liftObj;
						String code = lift.getString("registerCode");
						String name = lift.getString("liftName");
						log.info("name=" + name);
						EquipInfo info = new EquipInfo();
						if ("金鼎香樟苑".equals(lift.getString("nbhdName"))) {
							info.setProjectId("a04dd9c1073943cc8ad8480eaf4e44a3");
						} else {
							info.setProjectId("005b0c6662f6496da27681b55c4a1709");
						}
						//info.setTenantId(1L);
						info.setEquipName(name);
						info.setEquipCode(code);
						info.setEquipOutCode(code);
						info.setCollectorId("8fe0f3c474ba71c6d3789d143bb173c4");
						info.setAutoFlg(1);
						info.setEquipStatus(0);
						info.setSortId("eaebfce02b73b91726bd039026d13f84");
						info.setEquipPosition(name);
						info.setEquipModel("0");
						info.setEquipManufacturer("0");
						info.setNeedInspection(0);
						info.setNeedMaintenance(0);
						infos.add(info);
					}
				}
				if (infos.size() > 0) {
					equipInfoService.saveBatch(infos);
				}
			}
		}
		return Result.ok(result);
	}


	@AutoLog(value = "电梯设备视频播放地址查询")
	@ApiOperation(value="电梯设备视频播放地址查询", notes="电梯设备视频播放地址查询")
	@PostMapping(value = "/getLiftRealVedioUrl")
	public Result<String> getLiftRealVedioUrl(@RequestParam (name="registerCode") String registerCode,
											  @RequestParam(name="isHttps",defaultValue="0")  Boolean isHttps){
		String url = equipDataApiService.getLiftRealVedioUrl(registerCode,isHttps);
		return Result.ok(url);
	}

	@PostMapping(value = "/refreshRedis")
	public void refreshRedis(){
		equipInfoService.refreshToRedis();// 刷新redis中的设备信息
		equipCollectItemService.refreshToRedis();// 刷新reids中的采集项信息
		equipCollectItemDetailService.refreshToRedis();// 刷新redis中小区级别的采集项信息
		equipEventSortService.refreshToRedis();// 刷新redis中的事件分类信息
		equipEventSortDetailService.refreshToRedis();// 刷新redis中小区级别的事件分类信息
	}
}
